refactor: use gh aw logs for token analysis workflows#1884
Conversation
Replace manual artifact downloading (gh run download --name firewall-audit-logs) with gh aw logs --json in all 4 token analysis workflows. This aligns with the approach used by gh-aw's own token-audit and token-optimizer workflows. Benefits: - Eliminates dependency on knowing the correct artifact name (the root cause of the bug fixed in PR #1883) - Gets pre-aggregated structured data (token counts, costs, turns) instead of parsing raw token-usage.jsonl - Handles artifact naming backward/forward compat automatically - Pre-downloads data in steps block (faster, more reliable) Changes: - copilot-token-usage-analyzer.md: replaced manual run discovery + artifact download with gh aw logs --engine copilot --json pre-step - claude-token-usage-analyzer.md: same for --engine claude - copilot-token-optimizer.md: added gh aw logs --engine copilot pre-step for 7-day data, removed manual artifact download - claude-token-optimizer.md: same for --engine claude - shared/mcp/gh-aw.md: new shared component to install gh-aw CLI (mirroring upstream gh-aw's shared/mcp/gh-aw.md) Refs: #1883, github/gh-aw#25683 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
There was a problem hiding this comment.
Pull request overview
Refactors the Copilot/Claude token usage analyzer and optimizer workflows to rely on gh aw logs --json for structured, pre-aggregated token metrics instead of manually discovering runs and downloading/parsing artifacts. This reduces coupling to artifact naming/paths and aligns these workflows with the gh-aw recommended approach.
Changes:
- Added a shared workflow component to install the
gh awCLI extension for pre-agent steps. - Updated 4 token-analysis workflows to pre-download structured run/log data (
gh aw logs --engine … --json) and adjusted prompts to consume that JSON. - Removed the Azure blob domain from workflow network allowlists since artifacts are no longer downloaded directly.
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/shared/mcp/gh-aw.md | New shared component to install gh-aw and stage the binary for use in workflows. |
| .github/workflows/copilot-token-usage-analyzer.md | Switches analyzer data source to pre-downloaded gh aw logs --json output; updates prompt instructions accordingly. |
| .github/workflows/copilot-token-usage-analyzer.lock.yml | Compiled workflow reflecting the new import/steps and tightened allowed domains. |
| .github/workflows/copilot-token-optimizer.md | Switches optimizer artifact analysis to structured log JSON over a 7-day window; updates guidance. |
| .github/workflows/copilot-token-optimizer.lock.yml | Compiled workflow reflecting the new import/steps. |
| .github/workflows/claude-token-usage-analyzer.md | Switches analyzer data source to pre-downloaded gh aw logs --json output; updates prompt instructions accordingly. |
| .github/workflows/claude-token-usage-analyzer.lock.yml | Compiled workflow reflecting the new import/steps and tightened allowed domains. |
| .github/workflows/claude-token-optimizer.md | Switches optimizer artifact analysis to structured log JSON over a 7-day window; updates guidance. |
| .github/workflows/claude-token-optimizer.lock.yml | Compiled workflow reflecting the new import/steps. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 9/9 changed files
- Comments generated: 9
| # Install gh-aw if not already available | ||
| if ! gh aw --version >/dev/null 2>&1; then | ||
| echo "Installing gh-aw extension..." | ||
| curl -fsSL https://raw.githubusercontent.com/github/gh-aw/refs/heads/main/install-gh-aw.sh | bash |
There was a problem hiding this comment.
The install step downloads and executes a script from refs/heads/main via curl | bash, which is a supply-chain risk and makes builds non-reproducible. Prefer pinning to a specific commit/tag (or release asset) and verifying integrity (e.g., checksum/signature) before execution.
| curl -fsSL https://raw.githubusercontent.com/github/gh-aw/refs/heads/main/install-gh-aw.sh | bash | |
| GH_AW_REPO="https://github.com/github/gh-aw.git" | |
| GH_AW_COMMIT="0123456789abcdef0123456789abcdef01234567" | |
| GH_AW_TMPDIR="$(mktemp -d)" | |
| trap 'rm -rf "$GH_AW_TMPDIR"' EXIT | |
| git clone "$GH_AW_REPO" "$GH_AW_TMPDIR/gh-aw" | |
| git -C "$GH_AW_TMPDIR/gh-aw" checkout "$GH_AW_COMMIT" | |
| gh extension install "$GH_AW_TMPDIR/gh-aw" |
| --engine copilot \ | ||
| --start-date -1d \ | ||
| --json \ | ||
| -c 50 \ |
There was a problem hiding this comment.
This step claims to download the last 24 hours of runs, but -c 50 caps the results and can silently omit runs if more than 50 exist in the window. Consider removing the cap or making it explicit in the messaging/logic (and/or using pagination/max-runs appropriate for the period).
| -c 50 \ |
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
The workflow imports shared/mcp/gh-aw.md, which already sets GH_TOKEN using the GH_AW_* fallback chain, but this step overrides GH_TOKEN to secrets.GITHUB_TOKEN. If the repo relies on a higher-scope token (or runs on GHE with different requirements), this can break gh aw logs. Consider using the same fallback expression here, or omit GH_TOKEN so the component’s choice applies.
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| echo "\U0001F4E5 Downloading Claude workflow logs (last 24 hours)..." | ||
|
|
||
| LOGS_EXIT=0 | ||
| gh aw logs \ | ||
| --engine claude \ | ||
| --start-date -1d \ | ||
| --json \ | ||
| -c 50 \ | ||
| > /tmp/gh-aw/token-audit/claude-logs.json || LOGS_EXIT=$? |
There was a problem hiding this comment.
This step claims to download the last 24 hours of runs, but -c 50 caps the results and can silently omit runs if more than 50 exist in the window. Consider removing the cap or making it explicit in the messaging/logic (and/or using pagination/max-runs appropriate for the period).
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
The workflow imports shared/mcp/gh-aw.md, which already sets GH_TOKEN using the GH_AW_* fallback chain, but this step overrides GH_TOKEN to secrets.GITHUB_TOKEN. If the repo relies on a higher-scope token (or runs on GHE with different requirements), this can break gh aw logs. Consider using the same fallback expression here, or omit GH_TOKEN so the component’s choice applies.
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
|
||
| echo "\U0001F4E5 Downloading Copilot workflow logs (last 7 days)..." | ||
|
|
||
| LOGS_EXIT=0 | ||
| gh aw logs \ | ||
| --engine copilot \ | ||
| --start-date -7d \ | ||
| --json \ | ||
| -c 50 \ | ||
| > /tmp/gh-aw/token-audit/copilot-logs.json || LOGS_EXIT=$? | ||
|
|
||
| if [ -s /tmp/gh-aw/token-audit/copilot-logs.json ]; then | ||
| TOTAL=$(jq '.runs | length' /tmp/gh-aw/token-audit/copilot-logs.json) | ||
| echo "\u2705 Downloaded $TOTAL Copilot workflow runs (last 7 days)" |
There was a problem hiding this comment.
This step claims to download the last 7 days of runs, but -c 50 caps the results and can silently omit runs if more than 50 exist in the window. Consider removing the cap or making it explicit in the messaging/logic (and/or increasing the cap to match a 7-day lookback).
| echo "\U0001F4E5 Downloading Copilot workflow logs (last 7 days)..." | |
| LOGS_EXIT=0 | |
| gh aw logs \ | |
| --engine copilot \ | |
| --start-date -7d \ | |
| --json \ | |
| -c 50 \ | |
| > /tmp/gh-aw/token-audit/copilot-logs.json || LOGS_EXIT=$? | |
| if [ -s /tmp/gh-aw/token-audit/copilot-logs.json ]; then | |
| TOTAL=$(jq '.runs | length' /tmp/gh-aw/token-audit/copilot-logs.json) | |
| echo "\u2705 Downloaded $TOTAL Copilot workflow runs (last 7 days)" | |
| MAX_RUNS=50 | |
| echo "\U0001F4E5 Downloading Copilot workflow logs (last 7 days, up to $MAX_RUNS runs)..." | |
| LOGS_EXIT=0 | |
| gh aw logs \ | |
| --engine copilot \ | |
| --start-date -7d \ | |
| --json \ | |
| -c "$MAX_RUNS" \ | |
| > /tmp/gh-aw/token-audit/copilot-logs.json || LOGS_EXIT=$? | |
| if [ -s /tmp/gh-aw/token-audit/copilot-logs.json ]; then | |
| TOTAL=$(jq '.runs | length' /tmp/gh-aw/token-audit/copilot-logs.json) | |
| echo "\u2705 Downloaded $TOTAL Copilot workflow runs from the last 7 days (capped at $MAX_RUNS runs)" | |
| if [ "$TOTAL" -ge "$MAX_RUNS" ]; then | |
| echo "\u26a0\ufe0f Result count reached the configured cap of $MAX_RUNS runs; additional runs from the last 7 days may not be included" | |
| fi |
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
The workflow imports shared/mcp/gh-aw.md, which already sets GH_TOKEN using the GH_AW_* fallback chain, but this step overrides GH_TOKEN to secrets.GITHUB_TOKEN. If the repo relies on a higher-scope token (or runs on GHE with different requirements), this can break gh aw logs. Consider using the same fallback expression here, or omit GH_TOKEN so the component’s choice applies.
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| --engine claude \ | ||
| --start-date -7d \ | ||
| --json \ | ||
| -c 50 \ |
There was a problem hiding this comment.
This step claims to download the last 7 days of runs, but -c 50 caps the results and can silently omit runs if more than 50 exist in the window. Consider removing the cap or making it explicit in the messaging/logic (and/or increasing the cap to match a 7-day lookback).
| -c 50 \ |
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
The workflow imports shared/mcp/gh-aw.md, which already sets GH_TOKEN using the GH_AW_* fallback chain, but this step overrides GH_TOKEN to secrets.GITHUB_TOKEN. If the repo relies on a higher-scope token (or runs on GHE with different requirements), this can break gh aw logs. Consider using the same fallback expression here, or omit GH_TOKEN so the component’s choice applies.
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
Smoke Test Results — run 24257149635 ✅ GitHub MCP: "fix: token analyzers look for wrong artifact name" / "chore: upgrade gh-aw to v0.68.0 and auto-discover lock files" Overall: PASS
|
|
Smoke test report
|
Security Review✅ Net security improvementRemoval of network:
allowed:
- github
- - "*.blob.core.windows.net"This removes a wildcard Azure blob storage domain from the agent's egress allowlist, reducing the network attack surface. Good change.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Summary
Replaces manual artifact downloading with
gh aw logs --jsonin all 4 token analysis workflows. This aligns with the approach used by gh-aw's owncopilot-token-auditandcopilot-token-optimizerworkflows.Motivation
Our token workflows were manually discovering runs, downloading artifacts by name, and parsing raw
token-usage.jsonlfiles. This broke when the artifact name changed fromagent-artifactstofirewall-audit-logs(see #1883). Thegh aw logsCLI handles all of this correctly — it knows the correct artifact names (including backward compat), downloads and organizes data, and outputs structured JSON with pre-aggregated token metrics.Changes
New shared component
shared/mcp/gh-aw.md— Installs thegh awCLI (mirrors upstream gh-aw's component)Token Usage Analyzers (Copilot + Claude)
shared/mcp/gh-aw.mdimport andsteps:block withgh aw logs --engine <engine> --json*.blob.core.windows.netfrom network allowlistToken Optimizers (Copilot + Claude)
shared/mcp/gh-aw.mdimport andsteps:block with 7-day data pre-downloadgh run downloadwith pre-downloaded data filteringBenefits
Refs: #1883, github/gh-aw#25683