forge-dashboard

module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: GPL-3.0

README

forge-dashboard

CI release licence

A single-page dashboard of open pull requests, issues, and CI status across every repository you have write access to on GitHub and a Forgejo instance — one page instead of two forge UIs. See #1 for the full acceptance criteria this v1 was built against.

Design

  • No authentication. v1 assumes whatever network reaches this service is already trusted — a tailnet, a VPN, a firewall rule. There's no login system to bypass because there isn't one; don't expose this on the open internet.
  • Credentials never reach the browser. The Go backend holds both forges' tokens server-side and only ever hands the frontend its own already-filtered JSON. Confirm this yourself: open the browser's network tab and watch it call nothing but /api/dashboard and /healthz.
  • One Go binary, no frontend build step. Plain HTML/CSS/JS, embedded into the binary with //go:embed. go build is the whole pipeline — no Node toolchain needed to run the service, only to run its own lint/test tooling (see CONTRIBUTING.md).
  • Read-only. Nothing here writes back to either forge. It aggregates and displays; every row links out to the real thing.

Requirements

  • Go 1.27 or newer, to build.
  • A GitHub personal access token with read access to the repositories you want tracked (repo scope covers private repos; a fine-grained token needs Contents/Issues/Pull requests/Metadata read access) — or, with no token at all, a GitHub username to show that account's public repositories only (no credential involved; the same data anyone gets landing on github.com/<username>?tab=repositories). Verified live against a real 105-public-repo account; be aware unauthenticated GitHub API calls are capped at 60/hour, so this mode only sees everything on an account small enough to fit that budget — a token (5,000/hour) is what an account this size actually needs.
  • A Forgejo instance URL, plus either an API token (Settings → Applications → Generate New Token, scoped to read:repository and read:issue) or a username for that instance's public-repos-only fallback, same trade-off as GitHub's. Both GITHUB_* and FORGEJO_* are entirely independent and each optional on its own — run with just one forge configured, or neither (an empty dashboard) if that's ever useful for a smoke test.

Configuration

Everything is environment variables — no config file:

Variable Required Default Meaning
ADDR no :8080 Listen address.
GITHUB_TOKEN no* — A GitHub personal access token. Every repo it can push to is tracked, private included.
GITHUB_USERNAME no* — Used only when GITHUB_TOKEN is unset — shows that account's public repos, unauthenticated.
FORGEJO_URL no* — Base URL of the Forgejo instance, for example https://git.example.com.
FORGEJO_TOKEN no* — A Forgejo API token. Every repo it can push to is tracked, private included.
FORGEJO_USERNAME no* — Used only when FORGEJO_URL is set but FORGEJO_TOKEN isn't — that account's public repos only.
REFRESH_INTERVAL no 5m How often the backend re-polls both forges, as a Go duration (2m30s, 10m).

* Each forge is entirely optional, and GitHub and Forgejo don't depend on each other — configure one, both, or neither (the process still starts and serves an empty snapshot either way, rather than refusing to boot). Within a forge, its token wins over its username when both are set.

Repository discovery is automatic. With a token, the dashboard lists every repository it has push access to (GET /user/repos on both APIs); with only a username, it lists that account's public repositories (GET /users/<username>/repos, also both APIs) with no credential in play at all. Either way there's no per-repo allowlist to maintain.

Running it

go build -o forge-dashboard ./cmd/forge-dashboard
GITHUB_TOKEN=ghp_xxx FORGEJO_URL=https://git.example.com FORGEJO_TOKEN=xxx \
  ./forge-dashboard

Then open http://localhost:8080.

Docker
docker build -t forge-dashboard .
docker run --rm -p 8080:8080 \
  --cap-drop=ALL --security-opt=no-new-privileges --read-only \
  --memory=64m --cpus=0.5 \
  -e GITHUB_TOKEN=ghp_xxx -e FORGEJO_URL=https://git.example.com -e FORGEJO_TOKEN=xxx \
  forge-dashboard

The published image is ghcr.io/alrayyes/forge-dashboard, built and pushed on every release by .goreleaser.yml's dockers: block — tagged by version and :latest, linux/amd64 and linux/arm64.

Deployment

Deployed on a homelab, reachable only over Tailscale — the tailnet is the access boundary v1's "no authentication" design leans on. The image is pulled into that homelab's existing vps-docker compose setup as its own service directory, routed through the Traefik instance already running there; there's no per-service Tailscale sidecar, since every service on that host reaches the tailnet the same way. That deployment config lives in vps-docker, not here — this repo only has to produce the image.

API

api/openapi.yaml is the contract: GET /healthz for liveness, and GET /api/dashboard for the aggregated snapshot the frontend renders. redocly lint validates it; nothing yet asserts the handlers still match it (see CONTRIBUTING.md).

Contributing

See CONTRIBUTING.md for the toolchain, the hooks, and how a change gets reviewed and released.

Licence

GPL-3.0.

Directories

Path Synopsis
cmd
forge-dashboard command
Command forge-dashboard is the composition root: it builds a Source per configured forge, starts the aggregator's background refresh, and serves the API and static frontend against whatever the aggregator most recently assembled.
Command forge-dashboard is the composition root: it builds a Source per configured forge, starts the aggregator's background refresh, and serves the API and static frontend against whatever the aggregator most recently assembled.
internal
api
Package api is the composition root's one dependency: an http.Handler satisfying api/openapi.yaml, serving the aggregated dashboard snapshot and the static frontend.
Package api is the composition root's one dependency: an http.Handler satisfying api/openapi.yaml, serving the aggregated dashboard snapshot and the static frontend.
dashboard
Package dashboard holds the domain model both forge clients produce and the aggregator that merges them into one snapshot.
Package dashboard holds the domain model both forge clients produce and the aggregator that merges them into one snapshot.
forgejo
Package forgejo is a thin client for the pieces of the Forgejo API (Gitea-compatible) forge-dashboard needs — the same shape as internal/github, against a different API under a self-hosted host.
Package forgejo is a thin client for the pieces of the Forgejo API (Gitea-compatible) forge-dashboard needs — the same shape as internal/github, against a different API under a self-hosted host.
github
Package github is a thin client for the pieces of the GitHub REST API forge-dashboard needs: which repositories the token can write to, their open pull requests and issues, and combined CI status per pull request.
Package github is a thin client for the pieces of the GitHub REST API forge-dashboard needs: which repositories the token can write to, their open pull requests and issues, and combined CI status per pull request.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL