Skip to content

feat(github): serve multiple GitHub owners, each with its own auth#120

Merged
luthermonson merged 1 commit into
mainfrom
feat/multi-target-github
Jul 16, 2026
Merged

feat(github): serve multiple GitHub owners, each with its own auth#120
luthermonson merged 1 commit into
mainfrom
feat/multi-target-github

Conversation

@luthermonson

Copy link
Copy Markdown
Contributor

Summary

ephemerd could only serve one GitHub owner — a single [github] block with one owner + one credential. This lets a single daemon serve multiple owners at once, each with its own auth (e.g. an org via a GitHub App and a personal account via a PAT), so one runner can process jobs across accounts.

[github]                 # primary: an org via GitHub App
owner = "ephpm"
app_id = 3290288
installation_id = 121756633
private_key_path = "/etc/ephemerd/app.pem"
repos = ["ephemerd"]

[[github_extra]]         # additional owner via a PAT
owner = "luthermonson"
token = "ghp_..."        # (or GITHUB_TOKEN for the primary)
repos = ["card-cannon", "better"]

How

The scheduler already handles a list of providers, and each GitHub Client is fully self-contained per owner — so this needs no owner-routing surgery inside the client:

  • config: GitHubExtra []GitHubConfig + GitHubTargets() (primary [github] then [[github_extra]]) + per-target validation. Single [github] is unchanged.
  • initProviders: loop GitHubTargets(), building one provider per target (App or PAT). Each polls/registers only its owner's repos and registers JIT runners with its own credential.
  • webhook mode: each provider gets a stable, unique path — normally /webhook/github, disambiguated to /webhook/github/<owner> only when multiple GitHub targets exist. Single-target deployments keep the plain path (no change on upgrade).

Testing

  • New pkg/config tests for GitHubTargets() + multi-target validation; pkg/config, pkg/github, pkg/providers/github, pkg/scheduler all compile.
  • Verified live (poll mode): one config with ephpm (App) + luthermonson (PAT) authenticated to both; a self-hosted job queued in the private luthermonson/card-cannon was discovered only under the luthermonson target, while the ephpm (App) target correctly ignored it.

Notes

  • Job execution wasn't exercised here (needs the full runtime on a provisioned runner); this PR is the auth + per-owner discovery/routing layer.
  • Follow-up: the mayfly side renders [[github_extra]] into runner configs.

ephemerd could only serve one GitHub owner (a single [github] with one
owner + one credential). This adds [[github_extra]] targets so one daemon
can serve several owners at once, each with independent auth — e.g. an org
via a GitHub App and a personal account via a PAT.

- config: GitHubExtra []GitHubConfig + GitHubTargets() normalizer (primary
  [github] followed by [[github_extra]]) + per-target validation. The single
  [github] form is unchanged.
- initProviders: build one self-contained GitHub provider per target (App or
  PAT), appended to the existing provider list. Each provider polls/registers
  only its owner's repos and registers JIT runners with its own credential,
  so the scheduler routes jobs per owner with no cross-owner surgery.
- webhook mode: give each provider a stable, unique webhook path. Normally
  "/webhook/github"; with multiple GitHub targets it disambiguates by owner
  ("/webhook/github/<owner>") so they never collide on the mux or webhook URL.
  Single-target deployments keep the plain path (no change on upgrade).

Verified live in poll mode: one config with an org (App) + a personal
account (PAT) authenticated to both and discovered a queued job only in the
matching owner's repo.
@luthermonson
luthermonson force-pushed the feat/multi-target-github branch from 17ffe0d to b9e7be8 Compare July 16, 2026 00:06
@luthermonson
luthermonson merged commit 9ee9b1d into main Jul 16, 2026
6 of 8 checks passed
@luthermonson
luthermonson deleted the feat/multi-target-github branch July 16, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant