Skip to content

arddluma/GHAlyzer

Repository files navigation

GHAlyzer logo

GHAlyzer

Lightweight DevOps analytics for GitHub Actions.
Scan every repo under an owner/org and see which workflows are slow, flaky, or trending worse over time.

Live demo · Issues

Features

  • Live GitHub API — no database, no sync jobs, fully stateless
  • Multi-repo — iterates every repo under a user or org
  • Analytics — avg / p95 / max duration, failure rate, daily trend
  • Insights — human-readable callouts (bottlenecks, regressions, flaky workflows)
  • Dashboard — Next.js + Tailwind + Recharts
  • Verifiable builds — every production deploy is signed with a SLSA build provenance attestation you can independently verify
  • MCP server — use GHAlyzer as a tool inside Claude Desktop, Cursor, Windsurf, etc. via the Model Context Protocol

Use from an AI IDE (MCP)

GHAlyzer exposes an MCP server at https://ghalyzer.app/api/mcp. Ask Claude / Cursor / Windsurf things like "which workflows in vercel/next.js have the worst failure rate this month?" and it will call GHAlyzer directly — no login, public repos only.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "ghalyzer": {
      "url": "https://ghalyzer.app/api/mcp"
    }
  }
}

Cursor / Windsurf

Add a remote MCP server pointing at https://ghalyzer.app/api/mcp. No command, no args, no auth.

Tools exposed

Tool Purpose
list_public_repos List public non-archived repos under an owner.
scan_public_workflows Full analytics: avg/p95/max duration, failure rate, daily trend, insights.
get_public_insights Just the high-signal insights (slow/flaky/regressing workflows).

Rate-limited to 3 scans per 10 min per IP. Capped at 10 repos / 20 runs per call to stay within GitHub's unauthenticated API budget.

Verify the live build

Every commit pushed to main produces a signed SLSA v1 build provenance attestation that cryptographically binds the built artifact to this repository and commit. You can verify that ghalyzer.app is serving exactly what's in this repo — no trust in me required.

1. Check what the live site is running

curl -s https://ghalyzer.app/api/version
# {
#   "sha": "abc123…",
#   "repo": "arddluma/GHAlyzer",
#   "built_at": null
# }

The footer of every page shows the same commit SHA, linked to GitHub.

2. Verify the attestation

Install the GitHub CLI, then:

# Grab the artifact + attestation for the SHA from step 1
gh run download --repo arddluma/GHAlyzer --name ghalyzer-<sha>

# Verify it was built by this repo's workflow
gh attestation verify ghalyzer-<sha>.tar.gz \
  --repo arddluma/GHAlyzer \
  --source-ref refs/heads/main

A successful verification looks like:

✓ Verification succeeded!
  - Subject:       ghalyzer-<sha>.tar.gz
  - Predicate:     https://slsa.dev/provenance/v1
  - Source repo:   https://github.com/arddluma/GHAlyzer
  - Source commit: <sha>
  - Workflow:      .github/workflows/deploy.yml@refs/heads/main
  - Signer:        github-actions

If the site's /api/version SHA matches the artifact SHA you just verified, the live deploy was built from the public source code in this repo, by the workflow defined in .github/workflows/deploy.yml, and not tampered with. See all attestations →.

Quick start

yarn install
cp .env.example .env
# Register a GitHub App (see below) and fill in the required vars
yarn dev

Open http://localhost:3000, click Sign in with GitHub, then install the app on your accounts/orgs. The owner dropdown populates from your installations.

Environment

Var Required Description
GITHUB_APP_ID yes GitHub App numeric ID.
GITHUB_APP_CLIENT_ID yes GitHub App OAuth client ID.
GITHUB_APP_CLIENT_SECRET yes GitHub App OAuth client secret.
GITHUB_APP_PRIVATE_KEY yes PEM private key (multi-line, or single-line with \n).
GITHUB_APP_SLUG yes URL slug (the bit after github.com/apps/ on the install page).
SESSION_SECRET yes 32 random bytes, base64 (openssl rand -base64 32). Encrypts the session cookie.
TRUSTED_PROXY no 1 if behind a trusted reverse proxy (Vercel/nginx/Cloudflare) so rate limiting can key on real client IP.

GitHub App setup

  1. Go to https://github.com/settings/apps/new.
  2. Permissions → Repository:
    • Actions: Read-only
    • Metadata: Read-only (added automatically)
  3. Where can this GitHub App be installed?: Any account (or Only on this account for personal use).
  4. Identifying and authorizing users:
    • Callback URL: http://localhost:3000/api/github/callback
    • Request user authorization (OAuth) during installation
  5. Post-installation Setup URL: http://localhost:3000/api/github/callback
  6. Disable webhooks (we don't use them).
  7. Create the app. On the app's settings page:
    • Note the App IDGITHUB_APP_ID
    • Note the Client IDGITHUB_APP_CLIENT_ID
    • Generate a Client secretGITHUB_APP_CLIENT_SECRET
    • Generate a Private key (downloads a .pem) → paste its contents into GITHUB_APP_PRIVATE_KEY
    • The public page URL is https://github.com/apps/<slug> — that slug is GITHUB_APP_SLUG

Security model

  • The GitHub App private key never leaves the server. Installation access tokens are minted on demand (1h lifetime) and scoped to a single owner's installation.
  • Scopes requested: Actions: Read-only + Metadata: Read-only. The app literally cannot write to any repo, workflow, or secret.
  • User identity is established via a short-lived OAuth code flow; the resulting user-to-server token is used only to list the user's installations. It lives in an AES-256-GCM encrypted, HttpOnly, SameSite=Lax cookie with an 8-hour TTL.
  • Every call to /api/analytics or /api/repos re-verifies that the signed-in user actually has access to the requested installation (prevents IDOR).
  • No PAT entry in the UI; no server-side long-lived token; no GITHUB_OWNER allowlist needed — the authorization model is entirely delegated to GitHub App installations.

Deployment

  • Run behind a trusted reverse proxy (Vercel, nginx, Cloudflare) and set TRUSTED_PROXY=1 so the rate limiter can key on the real client IP. Otherwise the limiter applies a global quota only.
  • This repo uses Yarn. Install with yarn install --frozen-lockfile. Do not mix npm install or you risk a divergent dependency tree.
  • .env is gitignored — never commit your token.

API

All endpoints require the X-Requested-With: fetch header (anti-CSRF) and a valid session cookie (set via /api/github/login).

  • GET /api/session — current user { login, id, avatar_url } or { user: null }
  • GET /api/installations — installations the signed-in user has access to, plus install URL
  • GET /api/repos?owner=<name> — list repos for an installation
  • GET /api/analytics?owner=<name>&days=14&maxRepos=20&maxRunsPerRepo=100 — full analytics payload
  • POST /api/github/logout — clear the session cookie
  • GET /api/github/login — kick off OAuth flow (top-level redirect; not fetch-callable)

How durations are computed

duration_seconds = updated_at - run_started_at (falls back to created_at). This matches the wall-clock time of each workflow run visible in the Actions UI.

Notes

  • The tool only reads from GitHub — no writes, no persistence.
  • Large orgs: tune maxRepos and maxRunsPerRepo to stay under the 5k req/hr rate limit.

About

Lightweight DevOps analytics for GitHub Actions. Scan every repo under an owner/org and see which workflows are slow, flaky, or trending worse over time.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages