Import from GitHub: the GitHub App¶
Goal: pick repositories to import straight from GitHub, and build
private github.com repositories on your runners, without deploy
keys or personal-access tokens on the machines that build.
saggar.dev runs a GitHub App. It is separate from login: signing in with GitHub stays the plain OAuth provider (see Sign the CLI in). The App gives the account three things:
the repo listing the import page offers,
private-repo clones: the service mints a short-lived installation token when a runner claims the job, so the runner clones what its own credentials could never reach,
the app webhook, which keeps installations current.
1. Install the App on your repositories¶
Install the App on the repositories you want to import: your own account, or an org you administer. Adding repositories to the installation, or removing them, updates the listing; uninstalling detaches it.
Installations attach to accounts by the numeric GitHub account id their linked github identity already stores (logins rename; ids do not). A user installation matches that user’s account directly. An org installation matches no account, so the installing user (whoever clicked Install) stands in. An installation whose account matches no account still serves clone credentials; it just lists for no one.
2. Import from the listing¶
With the App installed, the import page’s GitHub provider reads the caller’s own installations:
$ curl -H "X-Auth-Token: sgt-…" \
https://saggar.dev/api/v1/forges/github/repositories
For each repository: the clone URL, full name, description and last
update. The listing is the caller’s own installations only; no
standing rules are invented. Nothing to list answers an empty list
plus a reason, rendered as-is, so the UI can show why nothing is
listed.
3. Private clones on your runners¶
A job cloning from github.com/<owner>/<repo> covered by an
installation is rewritten at claim time: the claim response’s source
URL carries a freshly minted installation token
(https://x-access-token:…@github.com/…). The runner needs no
GitHub credential at all. The token is valid for seconds, appears in
that one response only, and is never stored or logged; GitHub expires
it after an hour regardless. Public repositories keep their plain
clone URL.
A repo with a matching watch builds on every push as any other (see
Set up CI: watched repos, webhooks, statuses). Polling is plain git ls-remote, so it only sees the
refs the URL exposes without a credential; the claim-time token takes
the build’s own clone the rest of the way, and a repository webhook
brings private pushes in instantly (see Set up CI: watched repos, webhooks, statuses).