Documentation
¶
Overview ¶
Package githubapp turns a GitHub App's private key into short-lived installation tokens.
**Why this exists.** A personal access token in a Secret is long-lived, broadly scoped, and rotated by whoever remembers. An installation token is scoped to the installation and expires in an hour, which is the difference between a leaked credential being an incident and being a nuisance. For a tool whose pitch is that promotion should be evidence-gated rather than merge-rights-gated, holding a permanent write credential to every fleet repository is the weakest part of the threat model (#118).
An installation token works both as an API token and as a git password, so one source feeds the provider APIs and the git steps that push. Two credential paths would defeat the point.
Index ¶
Constants ¶
const ( KeyAppID = "appID" KeyClientID = "clientID" KeyInstallationID = "installationID" KeyPrivateKey = "privateKey" )
Secret keys a GitHub App credential is read from. Deliberately not `token`: a Secret carrying these is not interchangeable with one carrying a PAT, and a key that silently meant something else would be worse than a missing one.
Variables ¶
This section is empty.
Functions ¶
func HasAppKeys ¶
HasAppKeys reports whether a Secret looks like a GitHub App credential rather than a static token.
Types ¶
type Credentials ¶
type Credentials struct {
// Issuer is the App's client ID, or its numeric app ID. GitHub recommends
// the client ID and accepts both.
Issuer string
// InstallationID identifies which installation to mint a token for. An App
// installed on two organisations has two, and they are not interchangeable.
InstallationID string
// PrivateKey is the App's PEM-encoded RSA key.
PrivateKey []byte
// BaseURL is the API root, for GitHub Enterprise Server. Empty is
// api.github.com.
BaseURL string
}
Credentials are what a GitHub App needs to mint installation tokens.
func FromSecret ¶
func FromSecret(data map[string][]byte, baseURL string) (Credentials, error)
FromSecret reads credentials from a Secret's data.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source hands out a currently-valid installation token, minting and caching as needed.
Safe for concurrent use: several steps in one Passage can ask at once, and each mint is an API call worth not making twice.
func New ¶
func New(creds Credentials, client *http.Client) (*Source, error)
New builds a Source. It does not contact GitHub; the first Token call does.
func SourceFor ¶
func SourceFor(creds Credentials) (*Source, error)
SourceFor returns a shared Source for a credential, minting the hourly token once however many callers ask.
Package-level because the callers are deliberately independent: a Passage's git steps and its provider steps each resolve credentials on their own, and a cache per caller would mint a token per step against a rate limit shared with everything else the App does.
Keyed by the credential's content rather than by Secret name: rotating the key must produce a new Source, and two namespaces with the same Secret name must not share one.