Skip to content

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:

  1. Explicit config wins. If hosts."<host>".kind is set, that kind is used verbatim — no guessing.
  2. Otherwise auto-detect via guessKind(host) (packages/providers/src/index.ts):
Rule (checked in order)Result
host === "github.com" or ends with .github.comgithub
host === "gitlab.com" or ends with .gitlab.comgitlab
host === "codeberg.org"gitea
host label set (split on . and -) contains gitlabgitlab
host label set contains gitea or forgejogitea
host label set contains github or ghegithub
no matchgithub (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.comgitlab (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>".tokenEnv is 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:
KindDefault env vars (in order)
githubGITHUB_TOKEN, then GH_TOKEN
gitlabGITLAB_TOKEN
giteaGITEA_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 to fetch.maxTagsPerRepo tags 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 (network or notFound) 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:

jsonc
{
	"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

jsonc
{
	"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
		},
	},
}