Gitea integration — logged-in user sees their projects + issues in the atlas #4

Open
opened 2026-07-19 21:25:47 +00:00 by mathias · 1 comment
Owner

Goal

Once a user is authenticated (#3, Dex/OIDC), surface their own Gitea projects and issues inside cad-atlas — turning the static atlas into a personalized view where the CAD pipeline stages link to the user's real repos/issues/PRs.

Depends on

  • #3 (auth) — need the authenticated user identity to scope Gitea data. Closed — Authentik forward-auth gates atlas.d-ma.be at the ingress (not in-app OIDC middleware as originally scoped; identity headers X-authentik-username etc. are forwarded but unused here — see decision below).

Decision (2026-07-20) — static PAT, not per-visitor OAuth

cad-atlas is a single-operator homelab tool (one real user: Mathias). True per-user Gitea OAuth
token exchange is heavy machinery for a userbase of one. Went with: a server-held read-only
Gitea PAT (mirrors the DMABE_GITEA_API_TOKEN / tapir-session-secret pattern) driving calls
scoped to Mathias's own repos/issues. Anyone who clears Authentik forward-auth sees Mathias's
data — correct for this deployment, revisit only if cad-atlas ever gets a second real user with
different repo access.

Shipped (2026-07-20, b2761a4) — first slice: open issues on stage 03

  • internal/atlas/issues.goIssueNodes(), TDD'd pure parser: Gitea /repos/issues/search
    response → one stage node per issue (title, repo tag, clickable html_url).
  • internal/gitea/client.goMyIssues(), authenticated GET using GITEA_TOKEN env; returns
    an error (skip gracefully) when unset, mirroring the existing liveOverlay fallback pattern.
  • internal/web/handler.go — wired into liveOverlay(), merges onto stage 03 (Spec → Gitea issue, generate:"gitea-issues" in atlas.json).
  • Frontend: nodes with a url now render as clickable <a class="node"> instead of <div>.
  • Verified live end-to-end: real DMABE_GITEA_API_TOKEN against git.d-ma.be, stage 03 showed
    8 real open issues across infra/agentsquad/signals/cad-atlas with correct links. Without
    GITEA_TOKEN set, falls back to the 3 authored placeholder nodes (no crash) — confirmed both
    paths.

Not yet shipped

  • GITEA_TOKEN provisioning in prod — needs an ExternalSecret in mathias/infra
    k3s/apps/cad-atlas/ (mirror tapir-session-secret) + a scoped read-only PAT. Deferred:
    this session's mathias/infra local clone had a stale/expired git credential (auth
    failure on git pull), and secret-writes need their own explicit confirmation regardless.
    Until this lands, the overlay is inert in prod (graceful fallback, not broken).
  • User's own repos panel (only issues shipped this slice).
  • PRs panel.
  • Recent Actions runs, mapped per-repo (stage 06 already has this for cad-atlas's own repo
    via #5; this would generalize it across the user's repos).

Notes

Keep it read-only first. Respect Gitea's own visibility — satisfied here since the PAT is
Mathias's own account, so it only ever sees what Mathias can see.

## Goal Once a user is authenticated (#3, Dex/OIDC), surface **their own Gitea projects and issues** inside cad-atlas — turning the static atlas into a personalized view where the CAD pipeline stages link to the user's real repos/issues/PRs. ## Depends on - #3 (auth) — need the authenticated user identity to scope Gitea data. **Closed** — Authentik forward-auth gates `atlas.d-ma.be` at the ingress (not in-app OIDC middleware as originally scoped; identity headers `X-authentik-username` etc. are forwarded but unused here — see decision below). ## Decision (2026-07-20) — static PAT, not per-visitor OAuth cad-atlas is a single-operator homelab tool (one real user: Mathias). True per-user Gitea OAuth token exchange is heavy machinery for a userbase of one. Went with: a server-held read-only Gitea PAT (mirrors the `DMABE_GITEA_API_TOKEN` / tapir-session-secret pattern) driving calls scoped to Mathias's own repos/issues. Anyone who clears Authentik forward-auth sees Mathias's data — correct for this deployment, revisit only if cad-atlas ever gets a second real user with different repo access. ## Shipped (2026-07-20, b2761a4) — first slice: open issues on stage 03 - `internal/atlas/issues.go` — `IssueNodes()`, TDD'd pure parser: Gitea `/repos/issues/search` response → one stage node per issue (title, repo tag, clickable `html_url`). - `internal/gitea/client.go` — `MyIssues()`, authenticated GET using `GITEA_TOKEN` env; returns an error (skip gracefully) when unset, mirroring the existing `liveOverlay` fallback pattern. - `internal/web/handler.go` — wired into `liveOverlay()`, merges onto stage 03 (`Spec → Gitea issue`, `generate:"gitea-issues"` in `atlas.json`). - Frontend: nodes with a `url` now render as clickable `<a class="node">` instead of `<div>`. - Verified live end-to-end: real `DMABE_GITEA_API_TOKEN` against `git.d-ma.be`, stage 03 showed 8 real open issues across infra/agentsquad/signals/cad-atlas with correct links. Without `GITEA_TOKEN` set, falls back to the 3 authored placeholder nodes (no crash) — confirmed both paths. ## Not yet shipped - [ ] **`GITEA_TOKEN` provisioning in prod** — needs an ExternalSecret in `mathias/infra` `k3s/apps/cad-atlas/` (mirror `tapir-session-secret`) + a scoped read-only PAT. Deferred: this session's `mathias/infra` local clone had a stale/expired git credential (auth failure on `git pull`), and secret-writes need their own explicit confirmation regardless. Until this lands, the overlay is inert in prod (graceful fallback, not broken). - [ ] User's own **repos** panel (only issues shipped this slice). - [ ] **PRs** panel. - [ ] Recent Actions runs, mapped per-repo (stage 06 already has this for cad-atlas's own repo via #5; this would generalize it across the user's repos). ## Notes Keep it read-only first. Respect Gitea's own visibility — satisfied here since the PAT is Mathias's own account, so it only ever sees what Mathias can see.
Author
Owner

Update: auth is now Authentik forward-auth (#3), so the authenticated user identity arrives as request headers — no in-app OIDC needed. The ingress passes X-authentik-username, X-authentik-email, X-authentik-groups, X-authentik-uid to the app.

So this issue simplifies: read those headers → map the Authentik user to their Gitea account → call the Gitea API for that user's projects/issues (pass-through auth pattern, brain knowledge/mcp-pass-through-auth-pattern.md). Open question: how to get the user's Gitea token/identity from the Authentik identity (Gitea also auths via Authentik/Dex — likely a shared OIDC subject or an app-password exchange).

Update: auth is now Authentik **forward-auth** (#3), so the authenticated user identity arrives as request headers — no in-app OIDC needed. The ingress passes `X-authentik-username`, `X-authentik-email`, `X-authentik-groups`, `X-authentik-uid` to the app. So this issue simplifies: read those headers → map the Authentik user to their Gitea account → call the Gitea API for that user's projects/issues (pass-through auth pattern, brain `knowledge/mcp-pass-through-auth-pattern.md`). Open question: how to get the user's Gitea token/identity from the Authentik identity (Gitea also auths via Authentik/Dex — likely a shared OIDC subject or an app-password exchange).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/cad-atlas#4