Documentation
¶
Overview ¶
Package githubtokens is how another module asks the GitHub module for an installation token (docs/decisions/0071): a Minter port, the in-process implementation that holds the App's key and talks to GitHub, and the modcall pair (Register, Client) that carries the same call as the `github` module's `mint_installation` method.
The split is the decision and the credential. The issuer decides which grant a request is minted under and what it is narrowed to; whoever implements the Minter holds the App's private key, signs for it and calls GitHub. Until the GitHub module has a function of its own, the issuer's process holds the InProcess minter and nothing crosses a boundary; the pair is the seam the split will use, exercised today over modcall.Local.
Index ¶
Constants ¶
const ( Module = "github" MethodMintInstallation = "mint_installation" )
Module is the module that answers, and MethodMintInstallation its method.
const CallerIssuer = "issuer"
CallerIssuer is the one caller class that may ask for an installation token: the issuer decides the grant, and no other module has a reason to hold one.
Variables ¶
var ( // or uninstalled on GitHub since. ErrUnavailable = errors.New("that GitHub App cannot mint a token") // ErrScope is a narrowing wider than the installation: a repository the // installer did not select, or a permission they have not accepted. ErrScope = errors.New("the request is wider than any grant this proof holds") // ErrUpstream is GitHub failing, or the App's key failing. ErrUpstream = errors.New("GitHub did not mint the token") )
The refusals minting ends in. They are the issuer's (`invalid_target`, `invalid_scope`, `server_error`) and survive the module boundary by code.
Functions ¶
Types ¶
type AppStore ¶
type AppStore interface {
Get(ctx context.Context, id string) (catalogueapp.Record, string, bool, error)
}
AppStore is where a created App's record and key are kept.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a Minter in another module.
type InProcess ¶
type InProcess struct {
// Store is nil where the deployment keeps no catalogue Apps; every
// request is then refused as naming an App that cannot mint.
Store AppStore
// HTTP reaches GitHub. Nil uses a client with a thirty-second timeout.
HTTP *http.Client
// Now is the clock the App's JWT is signed against. Nil is time.Now.
Now func() time.Time
}
InProcess is the Minter that holds the keys: it reads the App, signs its JWT and calls GitHub.
type Minted ¶
type Minted struct {
Token string `json:"token"`
ExpiresAt time.Time `json:"expires_at"`
// Repositories and Permissions are what was granted, not what was asked.
Repositories []string `json:"repositories,omitempty"`
Permissions map[string]string `json:"permissions,omitempty"`
// Installation is the GitHub installation it was minted in, for the trail.
Installation int64 `json:"installation,omitempty"`
}
Minted is an installation token and what GitHub says it carries. It holds the secret; nothing logs it.
func (Minted) Granted ¶
func (m Minted) Granted() githubapp.MintedToken
Granted is the part GitHub minted, as the GitHub client spells it.
type Minter ¶
type Minter interface {
// MintInstallation mints for the request. The error wraps [ErrUnavailable],
// [ErrScope] or [ErrUpstream].
MintInstallation(ctx context.Context, r Request) (Minted, error)
}
Minter asks GitHub for an installation token.
type Request ¶
type Request struct {
// App is the catalogue id, without the `github-app:` prefix.
App string `json:"app"`
// Repositories are names within the installation's account; empty narrows
// to none.
Repositories []string `json:"repositories,omitempty"`
// Permissions are name to level; empty narrows to none.
Permissions map[string]string `json:"permissions,omitempty"`
}
Request is one installation token asked for: an App of the catalogue and what the token is cut down to. The decision is already made.