Providers
actup resolves every uses: ref through a host-specific provider. A provider knows how to list a repository's tags and resolve a ref to a commit SHA. Three provider kinds exist: GitHub, GitLab, and Gitea/Forgejo.
Host → provider resolution
For each host, the provider kind is chosen as:
- Explicit config wins. If
hosts."<host>".kindis set, that kind is used verbatim — no guessing. - Otherwise auto-detect via
guessKind(host)(packages/providers/src/index.ts):
| Rule (checked in order) | Result |
|---|---|
host === "github.com" or ends with .github.com | github |
host === "gitlab.com" or ends with .gitlab.com | gitlab |
host === "codeberg.org" | gitea |
host label set (split on . and -) contains gitlab | gitlab |
host label set contains gitea or forgejo | gitea |
host label set contains github or ghe | github |
| no match | github (fallback) |
Detection matches whole dot/dash-separated labels, not substrings: the host is lowercased and split on . and - into a label set. So gitlab.corp.example.com → gitlab (label gitlab present), but notgithub.com is not GitHub (notgithub is a single label, not github). Anything non-obvious should set hosts."<host>".kind explicitly.
The resolver is memoised per host and every provider is wrapped by the file cache (CachingProvider), honouring fetch.offline.
Authentication
The token for a host is selected by tokenFor(kind, tokenEnv):
- If
hosts."<host>".tokenEnvis set, only that single environment variable is read for that host. - Otherwise the kind's default env var list is used, first non-empty wins:
| Kind | Default env vars (in order) |
|---|---|
github | GITHUB_TOKEN, then GH_TOKEN |
gitlab | GITLAB_TOKEN |
gitea | GITEA_TOKEN |
If no token is found the provider runs unauthenticated (subject to the host's anonymous rate limits, and GitHub GraphQL is unavailable — see below).
GitHub
API base default: https://api.github.com. Auth header: Authorization: Bearer <token> plus X-GitHub-Api-Version: 2022-11-28.
GitHub supports two API modes, selected by fetch.apiMode:
graphql(default): one query fetches the default branch ref plus up tofetch.maxTagsPerRepotags in a single round-trip. GraphQL is only used when all of these hold:fetch.apiMode === "graphql", and- a token is present (GitHub GraphQL requires auth), and
fetch.maxTagsPerRepo <= 100.
If GraphQL fails with a soft error (
networkornotFound) it falls back to REST. Auth and rate-limit errors are fatal and are not retried via REST.rest: tag list + repo + commit endpoints. Always available (also the fallback path for the GraphQL conditions above).
Rate limiting: 403/429 with x-ratelimit-remaining: 0 (uses x-ratelimit-reset) or a Retry-After header is classified as a rate-limit error, not a generic network failure.
GitHub Enterprise (GHE)
GHE is just the GitHub provider pointed at a custom apiBase. Set:
{
"hosts": {
"ghe.corp.example": {
"kind": "github",
"apiBase": "https://ghe.corp.example/api/v3",
"tokenEnv": "GHE_TOKEN",
},
},
}The GraphQL endpoint is derived from the same apiBase origin: <protocol>//<host>/api/graphql. When no apiBase is set it defaults to https://api.github.com/graphql.
Why apiBase is HTTPS-only
apiBase is validated as a URL and refined to reject any non-https:// protocol (packages/core/src/config.ts). This is a deliberate token-exfiltration guard. The auth token is sent as an Authorization header to whatever apiBase points at. Config can be repo-resident — an attacker opening a pull request can add an actup.json to the repo. If apiBase were allowed to be http:// (or any cleartext endpoint), that attacker-controlled file could redirect your token to a host they control, in cleartext, over the network. Forcing https:// ensures the token only ever leaves over an encrypted channel to an endpoint that at least presents a valid TLS certificate. A bad apiBase value fails config validation with apiBase must use https://.
GitLab
API base default: https://<host>/api/v4. Auth header: PRIVATE-TOKEN: <token>. Default token env: GITLAB_TOKEN. Auto-detected for gitlab.com, *.gitlab.com, and any host whose label set contains gitlab. For self-hosted GitLab on a non-obvious domain, set kind: "gitlab" (and apiBase if the API is not at /api/v4).
Gitea / Forgejo
API base default: https://<host>/api/v1. Auth header: Authorization: token <token> (Gitea's token <...> scheme, not Bearer). Default token env: GITEA_TOKEN. Auto-detected for codeberg.org and any host whose label set contains gitea or forgejo. Forgejo is API-compatible with Gitea and uses the same provider — there is no separate Forgejo kind; configure kind: "gitea" for self-hosted Forgejo on a custom domain.
Per-host configuration summary
{
"defaultHost": "github.com",
"hosts": {
"git.example.org": {
"kind": "gitea", // overrides auto-detection
"apiBase": "https://git.example.org/api/v1", // https-only
"tokenEnv": "EXAMPLE_TOKEN", // sole env var read for this host
},
},
}